using System.Collections.Specialized;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows;
using System;
using WpfApp3.Tools.Helper;
using System.Collections;
using WpfApp3.Tools;

namespace WpfApp3.Controls;
[TemplatePart(Name = OverflowButtonKey, Type = typeof(ContextMenuToggleButton))]
[TemplatePart(Name = HeaderPanelKey, Type = typeof(TabPanel))]
[TemplatePart(Name = OverflowScrollviewer, Type = typeof(ScrollViewer))]
[TemplatePart(Name = ScrollButtonLeft, Type = typeof(ButtonBase))]
[TemplatePart(Name = ScrollButtonRight, Type = typeof(ButtonBase))]
[TemplatePart(Name = HeaderBorder, Type = typeof(Border))]
public class TabControl : System.Windows.Controls.TabControl
{
    private const string OverflowButtonKey = "PART_OverflowButton";

    private const string HeaderPanelKey = "PART_HeaderPanel";

    private const string OverflowScrollviewer = "PART_OverflowScrollviewer";

    private const string ScrollButtonLeft = "PART_ScrollButtonLeft";

    private const string ScrollButtonRight = "PART_ScrollButtonRight";

    private const string HeaderBorder = "PART_HeaderBorder";

    private ContextMenuToggleButton _buttonOverflow;

    internal TabPanel HeaderPanel { get; private set; }

    private ScrollViewer _scrollViewerOverflow;

    private ButtonBase _buttonScrollLeft;

    private ButtonBase _buttonScrollRight;

    private Border _headerBorder;





    /// <summary>
    /// 标签页位置的依赖属性
    /// </summary>
    public static readonly DependencyProperty TabPositionProperty =
        DependencyProperty.Register("TabPosition", typeof(TabPosition), typeof(TabControl),
            new FrameworkPropertyMetadata(TabPosition.Top, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure, OnTabPositionChanged));

    /// <summary>
    /// 处理标签页位置改变的回调方法
    /// </summary>
    /// <param name="d">依赖对象</param>
    /// <param name="e">包含新旧值的事件参数</param>
    private static void OnTabPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = (TabControl)d;
        control.UpdateTemplate();
    }
    /// <summary>
    /// 根据标签页位置更新控件模板
    /// </summary>
    private void UpdateTemplate()
    {
    }
    /// <summary>
    /// 获取或设置标签页的位置
    /// </summary>
    public TabPosition TabPosition
    {
        get { return (TabPosition)GetValue(TabPositionProperty); }
        set { SetValue(TabPositionProperty, value); }
    }

    /// <summary>
    /// 标签页是否可关闭的依赖属性
    /// </summary>
    public static readonly DependencyProperty IsClosableProperty =
        DependencyProperty.Register("IsClosable", typeof(bool), typeof(TabControl),
            new PropertyMetadata(true));

    /// <summary>
    /// 获取或设置标签页是否可以关闭
    /// </summary>
    public bool IsClosable
    {
        get { return (bool)GetValue(IsClosableProperty); }
        set { SetValue(IsClosableProperty, value); }
    }

    #region Events

    /// <summary>
    /// 标签页关闭前的路由事件
    /// </summary>
    public static readonly RoutedEvent ClosingEvent = EventManager.RegisterRoutedEvent(nameof(Closing), RoutingStrategy.Bubble, typeof(ClosingEventHandler), typeof(TabControl));

    /// <summary>
    /// 标签页关闭后的路由事件
    /// </summary>
    public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent(nameof(Closed), RoutingStrategy.Bubble, typeof(ClosedEventHandler), typeof(TabControl));

    /// <summary>
    /// 标签页关闭前事件
    /// </summary>
    public event ClosingEventHandler Closing
    {
        add { AddHandler(ClosingEvent, value); }
        remove { RemoveHandler(ClosingEvent, value); }
    }

    /// <summary>
    /// 标签页关闭后事件
    /// </summary>
    public event ClosedEventHandler Closed
    {
        add { AddHandler(ClosedEvent, value); }
        remove { RemoveHandler(ClosedEvent, value); }
    }

    #endregion


    /// <summary>
    ///     是否为内部操作
    /// </summary>
    internal bool IsInternalAction;

    /// <summary>
    ///     是否启用动画
    /// </summary>
    public static readonly DependencyProperty IsAnimationEnabledProperty = DependencyProperty.Register(
        nameof(IsAnimationEnabled), typeof(bool), typeof(TabControl), new PropertyMetadata(false));

    /// <summary>
    ///     是否启用动画
    /// </summary>
    public bool IsAnimationEnabled
    {
        get => (bool)GetValue(IsAnimationEnabledProperty);
        set => SetValue(IsAnimationEnabledProperty, value);
    }

    /// <summary>
    ///     是否可以拖动
    /// </summary>
    public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.Register(
        nameof(IsDraggable), typeof(bool), typeof(TabControl), new PropertyMetadata(false));

    /// <summary>
    ///     是否可以拖动
    /// </summary>
    public bool IsDraggable
    {
        get => (bool)GetValue(IsDraggableProperty);
        set => SetValue(IsDraggableProperty, value);
    }

    /// <summary>
    ///     是否显示关闭按钮
    /// </summary>
    public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.RegisterAttached(
        "ShowCloseButton", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));

    public static void SetShowCloseButton(DependencyObject element, bool value)
        => element.SetValue(ShowCloseButtonProperty, value);

    public static bool GetShowCloseButton(DependencyObject element)
        => (bool)element.GetValue(ShowCloseButtonProperty);

    /// <summary>
    ///     是否显示关闭按钮
    /// </summary>
    public bool ShowCloseButton
    {
        get => (bool)GetValue(ShowCloseButtonProperty);
        set => SetValue(ShowCloseButtonProperty, value);
    }

    /// <summary>
    ///     是否显示上下文菜单
    /// </summary>
    public static readonly DependencyProperty ShowContextMenuProperty = DependencyProperty.RegisterAttached(
        "ShowContextMenu", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));

    public static void SetShowContextMenu(DependencyObject element, bool value)
        => element.SetValue(ShowContextMenuProperty, value);

    public static bool GetShowContextMenu(DependencyObject element)
        => (bool)element.GetValue(ShowContextMenuProperty);

    /// <summary>
    ///     是否显示上下文菜单
    /// </summary>
    public bool ShowContextMenu
    {
        get => (bool)GetValue(ShowContextMenuProperty);
        set => SetValue(ShowContextMenuProperty, value);
    }

    public static readonly DependencyProperty CanBeClosedByMiddleButtonProperty =
        DependencyProperty.Register(nameof(CanBeClosedByMiddleButton), typeof(bool), typeof(TabControl), new PropertyMetadata(true));

    public bool CanBeClosedByMiddleButton
    {
        get => (bool)GetValue(CanBeClosedByMiddleButtonProperty);
        set => SetValue(CanBeClosedByMiddleButtonProperty, value);
    }
    /// <summary>
    ///     标签宽度
    /// </summary>
    public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
        nameof(ItemWidth), typeof(double), typeof(TabControl), new PropertyMetadata(150.0));

    /// <summary>
    ///     标签宽度
    /// </summary>
    public double ItemWidth
    {
        get => (double)GetValue(ItemWidthProperty);
        set => SetValue(ItemWidthProperty, value);
    }

    /// <summary>
    ///     标签高度
    /// </summary>
    public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
        nameof(ItemHeight), typeof(double), typeof(TabControl), new PropertyMetadata(35.0));

    /// <summary>
    ///     标签高度
    /// </summary>
    public double ItemHeight
    {
        get => (double)GetValue(ItemHeightProperty);
        set => SetValue(ItemHeightProperty, value);
    }

    /// <summary>
    ///     是否可以滚动
    /// </summary>
    public static readonly DependencyProperty IsScrollableProperty = DependencyProperty.Register(
        nameof(IsScrollable), typeof(bool), typeof(TabControl), new PropertyMetadata(false));

    /// <summary>
    ///     是否可以滚动
    /// </summary>
    public bool IsScrollable
    {
        get => (bool)GetValue(IsScrollableProperty);
        set => SetValue(IsScrollableProperty, value);
    }

    /// <summary>
    ///     是否显示溢出按钮
    /// </summary>
    public static readonly DependencyProperty ShowOverflowButtonProperty = DependencyProperty.Register(
        nameof(ShowOverflowButton), typeof(bool), typeof(TabControl), new PropertyMetadata(true));

    /// <summary>
    ///     是否显示溢出按钮
    /// </summary>
    public bool ShowOverflowButton
    {
        get => (bool)GetValue(ShowOverflowButtonProperty);
        set => SetValue(ShowOverflowButtonProperty, value);
    }

    /// <summary>
    ///     是否显示滚动按钮
    /// </summary>
    public static readonly DependencyProperty ShowScrollButtonProperty = DependencyProperty.Register(
        nameof(ShowScrollButton), typeof(bool), typeof(TabControl), new PropertyMetadata(false));

    /// <summary>
    ///     是否显示滚动按钮
    /// </summary>
    public bool ShowScrollButton
    {
        get => (bool)GetValue(ShowScrollButtonProperty);
        set => SetValue(ShowScrollButtonProperty, value);
    }

    public static readonly DependencyProperty OverflowMenuDisplayMemberPathProperty = DependencyProperty.Register(
        nameof(OverflowMenuDisplayMemberPath), typeof(string), typeof(TabControl), new PropertyMetadata(default(string)));

    public string OverflowMenuDisplayMemberPath
    {
        get => (string)GetValue(OverflowMenuDisplayMemberPathProperty);
        set => SetValue(OverflowMenuDisplayMemberPathProperty, value);
    }

    /// <summary>
    ///     可见的标签数量
    /// </summary>
    private int _itemShowCount;

    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnItemsChanged(e);

        if (HeaderPanel == null)
        {
            IsInternalAction = false;
            return;
        }

        UpdateOverflowButton();

        if (IsInternalAction)
        {
            IsInternalAction = false;
            return;
        }

        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            for (var i = 0; i < Items.Count; i++)
            {
                if (ItemContainerGenerator.ContainerFromIndex(i) is not TabItem item) return;
                item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                item.TabPanel = HeaderPanel;
            }
        }

        _headerBorder?.InvalidateMeasure();
        IsInternalAction = false;
    }

    public override void OnApplyTemplate()
    {
        if (_buttonOverflow != null)
        {
            if (_buttonOverflow.Menu != null)
            {
                _buttonOverflow.Menu.Closed -= Menu_Closed;
                _buttonOverflow.Menu = null;
            }

            _buttonOverflow.Click -= ButtonOverflow_Click;
        }

        if (_buttonScrollLeft != null) _buttonScrollLeft.Click -= ButtonScrollLeft_Click;
        if (_buttonScrollRight != null) _buttonScrollRight.Click -= ButtonScrollRight_Click;

        base.OnApplyTemplate();
        HeaderPanel = GetTemplateChild(HeaderPanelKey) as TabPanel;

        _buttonOverflow = GetTemplateChild(OverflowButtonKey) as ContextMenuToggleButton;
        _scrollViewerOverflow = GetTemplateChild(OverflowScrollviewer) as ScrollViewer;
        _buttonScrollLeft = GetTemplateChild(ScrollButtonLeft) as ButtonBase;
        _buttonScrollRight = GetTemplateChild(ScrollButtonRight) as ButtonBase;
        _headerBorder = GetTemplateChild(HeaderBorder) as Border;

        if (_buttonScrollLeft != null) _buttonScrollLeft.Click += ButtonScrollLeft_Click;
        if (_buttonScrollRight != null) _buttonScrollRight.Click += ButtonScrollRight_Click;

        if (_buttonOverflow != null)
        {
            var menu = new ContextMenu
            {
                Placement = PlacementMode.Bottom,
                PlacementTarget = _buttonOverflow
            };
            menu.Closed += Menu_Closed;
            _buttonOverflow.Menu = menu;
            _buttonOverflow.Click += ButtonOverflow_Click;
        }
    }

    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
        base.OnRenderSizeChanged(sizeInfo);
        UpdateOverflowButton();
    }

    private void UpdateOverflowButton()
    {
        double actualWidth = ActualWidth;
        double actualHeight = ActualHeight;
        double tabItemWidth = ItemWidth;
        double tabItemHeight = ItemHeight;
        var isVertical = TabPosition == TabPosition.Left || TabPosition == TabPosition.Right;
        if (isVertical)
        {

            _itemShowCount = (int)(actualHeight / tabItemHeight);
            _buttonOverflow?.Show(Items.Count > 0 && Items.Count * tabItemHeight >= actualHeight && ShowOverflowButton);
        }
        else {

            _itemShowCount = (int)(actualWidth / tabItemWidth);
            _buttonOverflow?.Show(Items.Count > 0 && Items.Count * tabItemWidth >= actualWidth && ShowOverflowButton);
        }
    }

    private void Menu_Closed(object sender, RoutedEventArgs e) => _buttonOverflow.IsChecked = false;

    private void ButtonScrollRight_Click(object sender, RoutedEventArgs e)
    {
        if (_scrollViewerOverflow == null) return;
        if (TabPosition == TabPosition.Left || TabPosition == TabPosition.Right)
        {
            var OffsetWidth = Math.Min(_scrollViewerOverflow.ContentVerticalOffset + ItemHeight, _scrollViewerOverflow.ScrollableHeight);
            _scrollViewerOverflow.ScrollToVerticalOffsetWithAnimation(OffsetWidth);
        }
        else
        {
            var OffsetWidth = Math.Min(_scrollViewerOverflow.CurrentHorizontalOffset + ItemWidth, _scrollViewerOverflow.ScrollableWidth);
            _scrollViewerOverflow.ScrollToHorizontalOffsetWithAnimation(OffsetWidth);
        }
    }

    private void ButtonScrollLeft_Click(object sender, RoutedEventArgs e)
    {
        if (_scrollViewerOverflow == null) return;
        if (TabPosition == TabPosition.Left || TabPosition == TabPosition.Right)
        {
            var OffsetHeight = Math.Max(_scrollViewerOverflow.ContentVerticalOffset - ItemHeight, 0);
            _scrollViewerOverflow.ScrollToVerticalOffsetWithAnimation(OffsetHeight);
        }
        else
        {
            var OffsetHeight = Math.Max(_scrollViewerOverflow.CurrentHorizontalOffset - ItemWidth, 0);
            _scrollViewerOverflow.ScrollToHorizontalOffsetWithAnimation(OffsetHeight);
        }
    }



    private void ButtonOverflow_Click(object sender, RoutedEventArgs e)
    {
        if (_buttonOverflow.IsChecked == true)
        {
            _buttonOverflow.Menu.Items.Clear();
            for (var i = 0; i < Items.Count; i++)
            {
                if (ItemContainerGenerator.ContainerFromIndex(i) is not TabItem item) continue;

                var menuItem = new Yuandl.ThemeUI.Controls.MenuItem
                {
                    HeaderStringFormat = ItemStringFormat,
                    IsChecked = item.IsSelected,
                    IsCheckable = true,
                    IsEnabled = item.IsEnabled
                };

                if (item.DataContext is not null)
                {
                    if (ItemTemplate is null)
                    {
                        menuItem.SetBinding(HeaderedItemsControl.HeaderProperty, new Binding(DisplayMemberPath)
                        {
                            Source = item.DataContext
                        });
                    }
                    else
                    {
                        menuItem.SetBinding(HeaderedItemsControl.HeaderProperty, new Binding(OverflowMenuDisplayMemberPath)
                        {
                            Source = item.DataContext
                        });
                    }
                }
                else
                {
                    menuItem.SetBinding(HeaderedItemsControl.HeaderProperty, new Binding(HeaderedItemsControl.HeaderProperty.Name)
                    {
                        Source = item
                    });
                }

                menuItem.Click += delegate
                {
                    _buttonOverflow.IsChecked = false;

                    var list = GetActualList();
                    if (list == null) return;

                    var actualItem = ItemContainerGenerator.ItemFromContainer(item);
                    if (actualItem == null) return;

                    var index = list.IndexOf(actualItem);
                    if (index >= _itemShowCount)
                    {
                        list.Remove(actualItem);
                        list.Insert(0, actualItem);
                        HeaderPanel.SetValue(TabPanel.FluidMoveDurationPropertyKey,
                            IsAnimationEnabled
                                ? new Duration(TimeSpan.FromMilliseconds(200))
                                : new Duration(TimeSpan.FromMilliseconds(0)));
                        HeaderPanel.ForceUpdate = true;
                        HeaderPanel.Measure(new Size(HeaderPanel.DesiredSize.Width, ActualHeight));
                        HeaderPanel.ForceUpdate = false;
                        SetCurrentValue(SelectedIndexProperty, 0);
                    }

                    item.IsSelected = true;
                };
                _buttonOverflow.Menu.Items.Add(menuItem);
            }
        }
    }

    internal double GetHorizontalOffset() => _scrollViewerOverflow?.CurrentHorizontalOffset ?? 0;
    /// <summary>
    /// 获取垂直滚动偏移量
    /// </summary>
    /// <returns>返回垂直滚动的偏移量</returns>
    internal double GetVerticalOffset() => _scrollViewerOverflow?.CurrentVerticalOffset ?? 0;

    internal void UpdateScroll() => _scrollViewerOverflow?.RaiseEvent(new MouseWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, 0)
    {
        RoutedEvent = MouseWheelEvent
    });

    internal void CloseAllItems() => CloseOtherItems(null);

    internal void CloseOtherItems(TabItem currentItem)
    {
        var actualItem = currentItem != null ? ItemContainerGenerator.ItemFromContainer(currentItem) : null;

        var list = GetActualList();
        if (list == null) return;

        IsInternalAction = true;

        for (var i = 0; i < Items.Count; i++)
        {
            var item = (TabItem)list[i];
            if (!Equals(item, actualItem) && item != null)
            {
                var argsClosing = new ClosingEventArgs(item);

                if (ItemContainerGenerator.ContainerFromItem(item) is not TabItem tabItem) continue;

                tabItem.RaiseEvent(argsClosing);
                if (argsClosing.Cancel)
                {
                    continue;
                }

                tabItem.RaiseEvent(new ClosedEventArgs(item));
                list.Remove(item);

                i--;
            }
        }

        SetCurrentValue(SelectedIndexProperty, Items.Count == 0 ? -1 : 0);
    }

    internal IList GetActualList()
    {
        IList list;
        if (ItemsSource != null)
        {
            list = ItemsSource as IList;
        }
        else
        {
            list = Items;
        }

        return list;
    }

    protected override bool IsItemItsOwnContainerOverride(object item) => item is TabItem;

    protected override DependencyObject GetContainerForItemOverride() => new TabItem();
}
